Research
Security News
Malicious PyPI Package ‘pycord-self’ Targets Discord Developers with Token Theft and Backdoor Exploit
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
webpack-merge
Advanced tools
The webpack-merge package provides a utility to merge multiple webpack configurations. It is useful for composing different webpack configurations for development, production, or any other purpose. It simplifies the process of combining configurations by smartly merging loaders, plugins, and other specific structures within the webpack configuration objects.
Merging basic configurations
This feature allows for the merging of two basic webpack configurations into one. It is useful for separating common configuration from environment-specific configurations.
const { merge } = require('webpack-merge');
const commonConfig = { entry: './src/app.js' };
const productionConfig = { mode: 'production' };
const mergedConfig = merge(commonConfig, productionConfig);
Merging with rules
This demonstrates merging configurations that include module rules. webpack-merge smartly combines the loaders, allowing for a nuanced configuration that can differ between development and production environments.
const { merge } = require('webpack-merge');
const commonConfig = { module: { rules: [ { test: /\.css$/, use: ['style-loader'] } ] } };
const productionConfig = { module: { rules: [ { test: /\.css$/, use: ['css-loader'] } ] } };
const mergedConfig = merge(commonConfig, productionConfig);
Customizing merge behavior
This feature allows for customizing the merge behavior, such as prepending or appending elements in arrays instead of the default merging strategy. It's particularly useful for fine-tuning the order of plugins or loaders.
const { mergeWithCustomize, customizeArray } = require('webpack-merge');
const commonConfig = { plugins: ['CommonPlugin'] };
const productionConfig = { plugins: ['ProductionPlugin'] };
const mergedConfig = mergeWithCustomize({ customizeArray: customizeArray({ 'plugins': 'prepend' }) })(commonConfig, productionConfig);
deepmerge is a library that can deeply merge multiple objects into one. While it's not specific to webpack configurations, it can be used for a similar purpose. However, webpack-merge offers webpack-specific merging capabilities that deepmerge does not, such as smart merging of loaders and plugins.
lodash.merge is a method from the Lodash library that provides a deep merge of objects. Similar to deepmerge, it can be used to merge webpack configurations but lacks the webpack-specific intelligence of webpack-merge, potentially requiring more manual configuration for complex webpack setups.
webpack-merge provides a merge
function that concatenates arrays and merges objects creating a new object. If functions are encountered, it will execute them, run the results through the algorithm, and then wrap the returned values within a function again.
This behavior is particularly useful in configuring webpack although it has uses beyond it. Whenever you need to merge configuration objects, webpack-merge can come in handy.
There's also a webpack specific merge variant known as merge.smart
that's able to take webpack specifics into account (i.e., it can flatten loader definitions).
merge(...configuration | [...configuration])
merge
is the core, and the most important idea, of the API. Often this is all you need unless you want further customization.
// Default API
var output = merge(object1, object2, object3, ...);
// You can pass an array of objects directly.
// This works with all available functions.
var output = merge([object1, object2, object3]);
// Please note that where keys match,
// the objects to the right take precedence:
var output = merge(
{ fruit: "apple", color: "red" },
{ fruit: "strawberries" }
);
console.log(output);
// { color: "red", fruit: "strawberries"}
merge({ customizeArray, customizeObject })(...configuration | [...configuration])
merge
behavior can be customized per field through a curried customization API.
// Customizing array/object behavior
var output = merge(
{
customizeArray(a, b, key) {
if (key === 'extensions') {
return _.uniq([...a, ...b]);
}
// Fall back to default merging
return undefined;
},
customizeObject(a, b, key) {
if (key === 'module') {
// Custom merging
return _.merge({}, a, b);
}
// Fall back to default merging
return undefined;
}
}
)(object1, object2, object3, ...);
For example, if the previous code was invoked with only object1
and object2
with object1
as:
{
foo1: ['object1'],
foo2: ['object1'],
bar1: { object1: {} },
bar2: { object1: {} },
}
and object2
as:
{
foo1: ['object2'],
foo2: ['object2'],
bar1: { object2: {} },
bar2: { object2: {} },
}
then customizeArray
will be invoked for each property of Array
type, i.e:
customizeArray(['object1'], ['object2'], 'foo1');
customizeArray(['object1'], ['object2'], 'foo2');
and customizeObject
will be invoked for each property of Object
type, i.e:
customizeObject({ object1: {} }, { object2: {} }, bar1);
customizeObject({ object1: {} }, { object2: {} }, bar2);
merge.unique(<field>, <fields>, field => field)
The first is the config property to look through for duplicates.
represents the values that should be unique when you run the field => field function on each duplicate.
const output = merge({
customizeArray: merge.unique(
'plugins',
['HotModuleReplacementPlugin'],
plugin => plugin.constructor && plugin.constructor.name
)
})({
plugins: [
new webpack.HotModuleReplacementPlugin()
]
}, {
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
// Output contains only single HotModuleReplacementPlugin now.
merge.strategy({ <field>: '<prepend|append|replace>''})(...configuration | [...configuration])
Given you may want to configure merging behavior per field, there's a strategy variant:
// Merging with a specific merge strategy
var output = merge.strategy(
{
entry: 'prepend', // or 'replace', defaults to 'append'
'module.rules': 'prepend'
}
)(object1, object2, object3, ...);
merge.smartStrategy({ <key>: '<prepend|append|replace>''})(...configuration | [...configuration])
The same idea works with smart merging too (described below in greater detail).
var output = merge.smartStrategy(
{
entry: 'prepend', // or 'replace'
'module.rules': 'prepend'
}
)(object1, object2, object3, ...);
merge.smart(...configuration | [...configuration])
webpack-merge tries to be smart about merging loaders when merge.smart
is used. Loaders with matching tests will be merged into a single loader value.
Note that the logic picks up webpack 2 rules
kind of syntax as well. The examples below have been written in webpack 1 syntax.
package.json
{
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},
// ...
}
webpack.config.js
var path = require('path');
var merge = require('webpack-merge');
var TARGET = process.env.npm_lifecycle_event;
var common = {
entry: path.join(__dirname, 'app'),
...
module: {
loaders: [
{
test: /\.css$/,
loaders: ['style', 'css'],
},
],
},
};
if(TARGET === 'start') {
module.exports = merge(common, {
module: {
// loaders will get concatenated!
loaders: [
{
test: /\.jsx?$/,
loader: 'babel?stage=1',
include: path.join(ROOT_PATH, 'app'),
},
],
},
...
});
}
if(TARGET === 'build') {
module.exports = merge(common, {
...
});
}
...
Loader string values loader: 'babel'
override each other.
merge.smart({
loaders: [{
test: /\.js$/,
loader: 'babel'
}]
}, {
loaders: [{
test: /\.js$/,
loader: 'coffee'
}]
});
// will become
{
loaders: [{
test: /\.js$/,
loader: 'coffee'
}]
}
Loader array values loaders: ['babel']
will be merged, without duplication.
merge.smart({
loaders: [{
test: /\.js$/,
loaders: ['babel']
}]
}, {
loaders: [{
test: /\.js$/,
loaders: ['coffee']
}]
});
// will become
{
loaders: [{
test: /\.js$/,
// appended because Webpack evaluated these from right to left
// this way you can specialize behavior and build the loader chain
loaders: ['babel', 'coffee']
}]
}
Loader array values loaders: ['babel']
can be reordered by including
original loaders.
merge.smart({
loaders: [{
test: /\.js$/,
loaders: ['babel']
}]
}, {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel']
}]
});
// will become
{
loaders: [{
test: /\.js$/,
// order of second argument is respected
loaders: ['react-hot', 'babel']
}]
}
This also works in reverse - the existing order will be maintained if possible:
merge.smart({
loaders: [{
test: /\.css$/,
use: [
{ loader: 'css-loader', options: { myOptions: true } },
{ loader: 'style-loader' }
]
}]
}, {
loaders: [{
test: /\.css$/,
use: [
{ loader: 'style-loader', options: { someSetting: true } }
]
}]
});
// will become
{
loaders: [{
test: /\.css$/,
use: [
{ loader: 'css-loader', options: { myOptions: true } },
{ loader: 'style-loader', options: { someSetting: true } }
]
}]
}
In the case of an order conflict, the second order wins:
merge.smart({
loaders: [{
test: /\.css$/,
use: [
{ loader: 'css-loader' },
{ loader: 'style-loader' }
]
}]
}, {
loaders: [{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' }
]
}]
});
// will become
{
loaders: [{
test: /\.css$/,
use: [
{ loader: 'style-loader' }
{ loader: 'css-loader' },
]
}]
}
Loader query strings loaders: ['babel?plugins[]=object-assign']
will be overridden.
merge.smart({
loaders: [{
test: /\.js$/,
loaders: ['babel?plugins[]=object-assign']
}]
}, {
loaders: [{
test: /\.js$/,
loaders: ['babel', 'coffee']
}]
});
// will become
{
loaders: [{
test: /\.js$/,
loaders: ['babel', 'coffee']
}]
}
Loader arrays in source values will have loader strings merged into them.
merge.smart({
loaders: [{
test: /\.js$/,
loader: 'babel'
}]
}, {
loaders: [{
test: /\.js$/,
loaders: ['coffee']
}]
});
// will become
{
loaders: [{
test: /\.js$/,
// appended because Webpack evaluated these from right to left!
loaders: ['babel', 'coffee']
}]
}
Loader strings in source values will always override.
merge.smart({
loaders: [{
test: /\.js$/,
loaders: ['babel']
}]
}, {
loaders: [{
test: /\.js$/,
loader: 'coffee'
}]
});
// will become
{
loaders: [{
test: /\.js$/,
loader: 'coffee'
}]
}
merge.multiple(...configuration | [...configuration])
Sometimes you may need to support multiple targets, webpack-merge will accept an object where each key represents the target configuration. The output becomes an array of configurations where matching keys are merged and non-matching keys are added.
var path = require('path');
var baseConfig = {
server: {
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.node.js'
}
},
client: {
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.js'
}
}
};
// specialized configuration
var production = {
client: {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash].js'
}
}
}
module.exports = merge.multiple(baseConfig, production)
Check out SurviveJS - Webpack and React to dig deeper into the topic.
npm i
npm run build
npm run watch
Before contributing, please open an issue where to discuss.
webpack-merge is available under MIT. See LICENSE for more details.
4.2.2 / 2019-08-27
npm audit warning
. #116merge.unique
documentation. #103FAQs
Variant of merge that's useful for webpack configuration
The npm package webpack-merge receives a total of 10,844,214 weekly downloads. As such, webpack-merge popularity was classified as popular.
We found that webpack-merge demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.